//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//


#ifndef __HOLDER_H_
#define __HOLDER_H_

#include <wincrypt.h>
#include "cor.h"
#include "genericstackprobe.h"
#include "staticcontract.h"
#include "volatile.h"
#include "palclr.h"
#include "clr_std/utility"
#include "clr_std/type_traits"

#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
#include <Activation.h>
#include <Inspectable.h>
#endif

// Note: you can't use CONTRACT's in this file. You can't use dynamic contracts because the impl of dynamic
// contracts depends on holders. You can't use static contracts because they include the function name as a string,
// and the template names in this file are just too long, so you get a compiler error.
//
// All the functions in this file are pretty basic, so the lack of CONTRACT's isn't a big loss.

#ifdef _MSC_VER
// Make sure we can recurse deep enough for FORCEINLINE
#pragma inline_recursion(on)
#pragma inline_depth(16)
#pragma warning(disable:4714)
#endif  // _MSC_VER

//------------------------------------------------------------------------------------------------
// Declare but do not define methods that would normally be automatically generated by the
// compiler. This will produce a link-time error if they are used. This is involved in object
// initialization and operator eliding; see
// http://groups.google.com/group/comp.lang.c++/msg/3cd673ab749bed83?dmode=source
// for the intricate details.

#ifdef __GNUC__
// GCC checks accessibility of the copy ctor before performing elision optimization, so
// it must be declared as public. VC does not, so we can declare it private to give an
// earlier error message.
#define HIDE_GENERATED_METHODS(_NAME)                                                       \
    public:                                                                                 \
        _NAME(_NAME const &);                                                               \
    private:                                                                                \
        _NAME & operator=(_NAME const &);
#else
#define HIDE_GENERATED_METHODS(_NAME)                                                       \
    private:                                                                                \
        _NAME(_NAME const &);                                                               \
        _NAME & operator=(_NAME const &);
#endif


#ifdef _DEBUG

#ifdef FEATURE_FUSION
namespace NATIVE_BINDER_SPACE
{
    class NativeAssembly;
}
#endif //FEATURE_FUSION

//------------------------------------------------------------------------------------------------
// This is used to make Visual Studio autoexp.dat work sensibly with holders again.
// The problem is that certain codebases (particulary Fusion) implement key data structures
// using a class but refer to it using a holder to an interface type. This combination prevents
// autoexp rules from working as desired.
// 
// Example: Take this useful autoexp rule for CAssemblyName.
//
//   CAssemblyName=<_rProp._rProp[3].asStr>
//
// To get the same rule to fire when your assemblyname is wrapped in a ReleaseHolder,
// add these companion rules.
//
//    HolderBase<CAssemblyName *>=<m_value->_rProp._rProp[3].asStr>
//    HolderBase<IAssemblyName *>=<m_pAutoExpVisibleValue->_asCAssemblyName->_rProp._rProp[3].asStr>
//
//------------------------------------------------------------------------------------------------
struct AutoExpVisibleValue
{
  private:
    union
    {
        // Only include a class name here if it is customarily referred to through an abstract interface.
#ifdef FEATURE_FUSION
        const class CAssemblyName                           *_asCAssemblyName;
        const class CAssembly                               *_asCAssembly;
        const class CAssemblyManifestImport                 *_asCAssemblyManifestImport;
        const class CAssemblyModuleImport                   *_asCAssemblyModuleImport;
        const class CHostAssembly                           *_asCHostAssembly;
        const class CHostAssemblyModuleImport               *_asCHostAssemblyModuleImport;
        const class BindResult                              *_asBindResult;
        const class BindContext                             *_asBindContext;
        const class NATIVE_BINDER_SPACE::NativeAssembly     *_asNativeAssembly;
        const class AssemblyLocation                        *_asAssemblyLocation;
#endif //FEATURE_FUSION

#if defined(FEATURE_HOSTED_BINDER) && defined(FEATURE_APPX)
        const class AppXBindResultImpl                      *_asAppXBindResultImpl;
#endif

#ifndef FEATURE_CORECLR
        const class PEFingerprint                           *_asPEFingerprint;
#endif //!FEATURE_CORECLR
        const void                                          *_pPreventEmptyUnion;
    };
};
#endif //_DEBUG

//-----------------------------------------------------------------------------
// Holder is the base class of all holder objects.  Any backout object should derive from it.
// (Eventually some additional bookeeping and exception handling code will be placed in this 
// base class.)
//
// There are several ways to use this class:
//  1. Derive from HolderBase, and instantiate a Holder or Wrapper around your base.  This is necessary
//      if you need to add more state to your holder.
//  2. Instantiate the Holder template with your type and functions.
//  3. Instantiate the Wrapper template with your type and functions.  The Wrapper adds some additional
//      operator overloads to provide "smart pointer" like behavior
//  4. Use a prebaked Holder.  This is ALWAYS the preferable strategy.  It is expected that
//      the general design patter is that Holders will be provided as part of a typical data abstraction. 
//      (See Crst for an example of this.)
//-----------------------------------------------------------------------------



//-----------------------------------------------------------------------------
// HolderBase defines the base holder functionality. You can subtype and plug in 
// a different base if you need to add more members for access during 
// acquire & release
//-----------------------------------------------------------------------------
template <typename TYPE>
class HolderBase
{
  protected:
    TYPE    m_value;
  
    HolderBase(TYPE value)
      : m_value(value)
    {
        // TODO: Find a way to enable this check.
        // We can have a holder in SO tolerant, then probe, then acquire a value.  This works
        // because the dtor is guaranteed to run with enough stack.
        // EnsureSOIntolerantOK(__FUNCTION__, __FILE__, __LINE__);

#ifdef _DEBUG
        m_pAutoExpVisibleValue = (const AutoExpVisibleValue *)(&m_value);
#endif //_DEBUG
    }

    void DoAcquire()
    {
        // Insert any global or thread bookeeping here
    }

    void DoRelease()
    {
        // Insert any global or thread bookeeping here
    }

#ifdef _DEBUG
 private:
    // NOT DEAD CODE: This field is not referenced in the source code but it is not a dead field. See comments above "class AutoExpVisibleValue" for why this field exists.
    // Note: What we really want is for m_value and m_pAutoExpVisibleValue to be members of a union. But the compiler won't let you build that
    //       since it can't prove that "TYPE" doesn't have a non-trivial constructor.
    const AutoExpVisibleValue *m_pAutoExpVisibleValue;  // This field is to be referenced from individual autoexp.dat files, NOT from the CLR source code.
#endif //_DEBUG

};  // class HolderBase<>

#ifndef _PREFAST_ // Work around an ICE error in EspX.dll

template <typename TYPE>
BOOL CompareDefault(TYPE value, TYPE defaultValue)
{
    STATIC_CONTRACT_SUPPORTS_DAC; 
    return value == defaultValue;
}

#else

template <typename TYPE>
BOOL CompareDefault(TYPE value, TYPE defaultValue)
{
    return FALSE;
}

#endif


template <typename TYPE>
BOOL NoNull(TYPE value, TYPE defaultValue)
{
    return FALSE;
}

// Used e.g. for retail version of code:SyncAccessHolder
template <typename TYPE> 
class NoOpBaseHolder
{
  public:
    FORCEINLINE NoOpBaseHolder() 
    {
    }
    FORCEINLINE NoOpBaseHolder(TYPE value, BOOL take = TRUE) 
    {
    }
    FORCEINLINE ~NoOpBaseHolder() 
    {
    }
    FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
    {
    }
    FORCEINLINE void Acquire()
    {
    }
    FORCEINLINE void Release()
    {
    }
    FORCEINLINE void Clear()
    {
    }
    FORCEINLINE void SuppressRelease()
    {
    }
    FORCEINLINE TYPE Extract()
    {
    }
    FORCEINLINE TYPE GetValue()
    {
    }
    FORCEINLINE BOOL IsNull() const
    {
        return FALSE;
    }

  private:
    NoOpBaseHolder& operator=(NoOpBaseHolder const &);
    NoOpBaseHolder(NoOpBaseHolder const &);
};  // NoOpBaseHolder<>


template
    <
        typename TYPE,
        typename BASE,
        UINT_PTR DEFAULTVALUE = 0,
        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
        HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq
    >
class BaseHolder : protected BASE
{
  protected:
    BOOL    m_acquired;      // Have we acquired the resource?

    static_assert(!std::is_pointer<TYPE>::value || DEFAULTVALUE == 0 || DEFAULTVALUE == UINT_PTR(-1 /*INVALID_HANDLE_VALUE*/),
                  "DEFAULTVALUE must be NULL for pointer holders and wrappers.");

  public:
    FORCEINLINE BaseHolder() 
      : BASE(TYPE(DEFAULTVALUE)), 
        m_acquired(FALSE)
    {
    }
    FORCEINLINE BaseHolder(TYPE value)
      : BASE(value), 
        m_acquired(FALSE)
    {
        if (!IsNull())
            Acquire();
    }
    FORCEINLINE BaseHolder(TYPE value, BOOL takeOwnership) 
      : BASE(value), 
        m_acquired(FALSE)
    {
        if (takeOwnership)
            Acquire();
    }
    FORCEINLINE ~BaseHolder() 
    {
        Release();
    }
    // Sets the value to 'value'. Doesn't call Acquire if value is DEFAULTVALUE.
    FORCEINLINE void Assign(TYPE value)
    {
        Assign(value, !IS_NULL(value, TYPE(DEFAULTVALUE)));
    }
    // Sets the value to 'value'. Doesn't call Acquire if fTake is FALSE.
    FORCEINLINE void Assign(TYPE value, BOOL takeOwnership)
    {
        Release();
        this->m_value = value;
        if (takeOwnership)
            Acquire();
    }
    FORCEINLINE void Acquire()
    {
        STATIC_CONTRACT_WRAPPER;
        _ASSERTE(!m_acquired);

        if (!IsNull())
        {
            this->DoAcquire();
            m_acquired = TRUE;
        }
    }
    FORCEINLINE void Release()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_acquired)
        {
            _ASSERTE(!IsNull());
        
            if (VALIDATION_TYPE != HSV_NoValidation)
            {
                VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
                this->DoRelease();
            }
            else
            {
                this->DoRelease();
            }
            m_acquired = FALSE;
        }
    }

    FORCEINLINE void Clear()
    {
        STATIC_CONTRACT_WRAPPER;
        Assign(TYPE(DEFAULTVALUE), FALSE);
    }
    FORCEINLINE void SuppressRelease()
    {
        STATIC_CONTRACT_LEAF;
        m_acquired = FALSE;
    }
    FORCEINLINE TYPE Extract()
    {
        STATIC_CONTRACT_WRAPPER;
        SuppressRelease();
        return GetValue();
    }
    FORCEINLINE TYPE GetValue()
    {
        STATIC_CONTRACT_LEAF;
        return this->m_value;
    }
    FORCEINLINE BOOL IsNull() const
    {
        STATIC_CONTRACT_WRAPPER;
        return IS_NULL(this->m_value, TYPE(DEFAULTVALUE));
    }

    HIDE_GENERATED_METHODS(BaseHolder)
};  // BaseHolder<>

template <void (*ACQUIRE)(), void (*RELEASEF)(), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
class StateHolder
{
  private:
    BOOL    m_acquired;      // Have we acquired the state?

  public:
    FORCEINLINE StateHolder(BOOL take = TRUE) 
      : m_acquired(FALSE)
    {
        STATIC_CONTRACT_WRAPPER;
        if (take)
            Acquire();
    }
    FORCEINLINE ~StateHolder() 
    {
        STATIC_CONTRACT_WRAPPER;
        Release();
    }
    FORCEINLINE void Acquire()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookeeping here

        _ASSERTE(!m_acquired);

        ACQUIRE();
        m_acquired = TRUE;
    }
    FORCEINLINE void Release()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookeeping here

        if (m_acquired)
        {
            if (VALIDATION_TYPE != HSV_NoValidation)
            {
                VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
                RELEASEF();
            }
            else
            {
                RELEASEF();
            }
            m_acquired = FALSE;
        }
    }
    FORCEINLINE void Clear()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_acquired)
        {
            RELEASEF();
        }

        m_acquired = FALSE;
    }
    FORCEINLINE void SuppressRelease()
    {
        STATIC_CONTRACT_LEAF;
        m_acquired = FALSE;
    }

    HIDE_GENERATED_METHODS(StateHolder)
};  // class StateHolder<>

// Holder for the case where the acquire function can fail.
template <typename VALUE, BOOL (*ACQUIRE)(VALUE value), void (*RELEASEF)(VALUE value), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
class ConditionalStateHolder
{
  private:
    VALUE   m_value;
    BOOL    m_acquired;      // Have we acquired the state?

  public:
    FORCEINLINE ConditionalStateHolder(VALUE value, BOOL take = TRUE) 
      : m_value(value), m_acquired(FALSE)
    {
        STATIC_CONTRACT_WRAPPER;
        if (take)
            Acquire();
    }
    FORCEINLINE ~ConditionalStateHolder() 
    {
        STATIC_CONTRACT_WRAPPER;
        Release();
    }
    FORCEINLINE BOOL Acquire()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookeeping here

        _ASSERTE(!m_acquired);

        m_acquired = ACQUIRE(m_value);
        
        return m_acquired;
    }
    FORCEINLINE void Release()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookeeping here

        if (m_acquired)
        {
            if (VALIDATION_TYPE != HSV_NoValidation)
            {
                VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
                RELEASEF(m_value);
            }
            else
            {
                RELEASEF(m_value);
            }
            m_acquired = FALSE;
        }
    }
    FORCEINLINE void Clear()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_acquired)
        {
            RELEASEF(m_value);
        }

        m_acquired = FALSE;
    }
    FORCEINLINE void SuppressRelease()
    {
        STATIC_CONTRACT_LEAF;
        m_acquired = FALSE;
    }
    FORCEINLINE BOOL Acquired()
    {
        STATIC_CONTRACT_LEAF;

        return m_acquired;
    }

    HIDE_GENERATED_METHODS(ConditionalStateHolder)
};  // class ConditionalStateHolder<>


// Making the copy constructor private produces a warning about "can't generate copy
// constructor" on all holders (duh, that's the point.)
#ifdef _MSC_VER
#pragma warning(disable:4511)
#endif  // _MSC_VER

//-----------------------------------------------------------------------------
// BaseWrapper is just Base like a Holder, but it "transparently" proxies the type it contains,
// using operator overloads.  Use this when you want a holder to expose the functionality of 
// the value it contains.
//-----------------------------------------------------------------------------
template <typename TYPE, typename BASE,
          UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq> 
class BaseWrapper : public BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
{
    typedef BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;


#ifdef __GNUC__
//#pragma GCC visibility push(hidden)
#endif // __GNUC__
    // This temporary object takes care of the case where we are initializing 
    // a holder's contents by passing it as an out parameter.  The object is 
    // guaranteed to live longer than the call it is passed to, hence we should
    // properly acquire the object on return
    friend class AddressInitHolder;
    class AddressInitHolder
    {
      protected:
        BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &m_holder;

      public:
        FORCEINLINE AddressInitHolder(BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &holder) 
          : m_holder(holder) 
        {
            //
            // We must clear the value, to avoid the following scenario:
            //
            //      ReleaseHolder<MyType> pMyType;
            //      hr = MyFunction(&pMyType, ...);
            //      <do something with pMyType>
            //      hr = MyFunction(&pMyType, ...); <- calls Release before call and Acquire on return.
            //
            // If the second call to MyFunction were to fail and return without updating the
            // out parameter, then ~AddressInitHolder will all Acquire, which is a no-op on
            // the underlying pointer but sets m_acquired to TRUE. Thus, when pMyType goes
            // out of scope, ReleaseHolder will cause a double-release of pMyType.
            //
            // By calling Clear, then the call to Acquire in the dtor will not set m_acquired
            // to true since IsNull(m_holder.m_value) will return true.
            //
            m_holder.Clear();
        }
        FORCEINLINE ~AddressInitHolder()
        {
            m_holder.Acquire();
        }

        // It's not optimal to have to declare these casting operators.  But if we don't, 
        // people cannot cast the result of &holder to these values.  (The C++ compiler won't
        // automatically use the TYPE * cast as an intermediate value.)  So we put them here,
        // rather than forcing callers to double cast in these common cases.

        FORCEINLINE operator IUnknown **()
        {
            IUnknown *unknown;
            // Typesafe check.  This will fail at compile time if
            // m_holder.m_value can't be converted to an IUnknown *.
            unknown = static_cast<IUnknown*>(m_holder.m_value);
            // do the cast with an unsafe cast
            return (IUnknown **)(&m_holder.m_value);
        }

#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
        FORCEINLINE operator IInspectable **()
        {
            IInspectable *inspectable;
            // Typesafe check.  This will fail at compile time if
            // m_holder.m_value can't be converted to an IInspectable *.
            inspectable = static_cast<IInspectable *>(m_holder.m_value);
            return (IInspectable **)(&m_holder.m_value);

        }
#endif // FEATURE_COMINTEROP

        FORCEINLINE operator void **()
        {
            return (void **)(&m_holder.m_value);
        }
        FORCEINLINE operator void *()
        {
            return (void *)(&m_holder.m_value);
        }
    };
    
    // Separate out method with TYPE * cast operator, since it may clash with IUnknown ** or 
    // void ** cast operator.
    friend class TypedAddressInitHolder;
    class TypedAddressInitHolder : public AddressInitHolder
    {
      public:
        FORCEINLINE TypedAddressInitHolder(BaseWrapper & holder) 
          : AddressInitHolder(holder)
        {
        }

        FORCEINLINE operator TYPE *()
        {
            return static_cast<TYPE *>(&this->m_holder.m_value);
        }
    };
#ifdef __GNUC__
//#pragma GCC visibility pop
#endif // __GNUC__
    
  public:
    FORCEINLINE BaseWrapper()
        : BaseT(TYPE(DEFAULTVALUE), FALSE)
    {
    }
    FORCEINLINE BaseWrapper(TYPE value)
        : BaseT(value)
    {
    }
    FORCEINLINE BaseWrapper(TYPE value, BOOL take)
        : BaseT(value, take)
    {
    }
    FORCEINLINE BaseWrapper& operator=(TYPE value)
    {
        BaseT::Assign(value);
        return *this;
    }
    FORCEINLINE operator TYPE() const
    {
        return this->m_value;
    }
    FORCEINLINE TypedAddressInitHolder operator&()
    {
        return TypedAddressInitHolder(*this);
    }
    template <typename T>
    FORCEINLINE bool operator==(T const & value) const
    {
        return !!(this->m_value == TYPE(value));
    }
    template <typename T>
    FORCEINLINE bool operator!=(T const & value) const
    {
        return !!(this->m_value != TYPE(value));
    }
    FORCEINLINE const TYPE &operator->() const
    {
        return this->m_value;
    }
    FORCEINLINE int operator!() const
    {
        return this->IsNull();
    }

  private:
    HIDE_GENERATED_METHODS(BaseWrapper)
};  // class BaseWrapper<>

//-----------------------------------------------------------------------------
// Generic templates to use to wrap up acquire/release functionality for Holder
//----------------------------------------------------------------------------- 

template <typename TYPE>
FORCEINLINE void DoNothing(TYPE value)
{
    // @TODO: Due to prefast template problems, implementations of the DoNothing macro have been changed
    // Search by prefast, and remove them when prefast is ready
}

FORCEINLINE void DoNothing()
{
}

// Prefast stuff.We should have DoNothing<type*> in the holder declaration, but currently
// prefast doesnt support, it, so im stuffing all these here so if we need to change the template you can change
// everything here. When prefast works, remove the following functions
struct ConnectionCookie;
FORCEINLINE void ConnectionCookieDoNothing(ConnectionCookie* p)
{
}

class ComCallWrapper;
FORCEINLINE void CCWHolderDoNothing(ComCallWrapper* p)
{
}


FORCEINLINE void DispParamHolderDoNothing(VARIANT* p)
{
}

FORCEINLINE void VariantPtrDoNothing(VARIANT* p)
{
}

FORCEINLINE void VariantDoNothing(VARIANT)
{
}

FORCEINLINE void ZeroDoNothing(VOID* p)
{
}

class CtxEntry;
FORCEINLINE void CtxEntryDoNothing(CtxEntry* p)
{
}

struct RCW;
FORCEINLINE void NewRCWHolderDoNothing(RCW*)
{
}

// Prefast stuff.We should have DoNothing<SafeArray*> in the holder declaration
FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p)
{
}




//-----------------------------------------------------------------------------
// Holder/Wrapper are the simplest way to define holders - they synthesizes a base class out of 
// function pointers
//-----------------------------------------------------------------------------

template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>  
class FunctionBase : protected HolderBase<TYPE>
{
  protected:

    FORCEINLINE FunctionBase(TYPE value)
      : HolderBase<TYPE>(value)
    {
    }

    FORCEINLINE void DoAcquire()
    {
        ACQUIREF(this->m_value);
    }

    void DoRelease()
    {
        // <TODO> Consider removing this stack validation since it is redundant with the
        // one that is already being done in BaseHolder & BaseWrapper. </TODO>
        if (VALIDATION_TYPE != HSV_NoValidation)
        {
            VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
            RELEASEF(this->m_value);
        }
        else
        {
            RELEASEF(this->m_value);
        }
    }
};  // class Function<>

template
    <
        typename TYPE,
        void (*ACQUIREF)(TYPE),
        void (*RELEASEF)(TYPE),
        UINT_PTR DEFAULTVALUE = 0, 
        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
        HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq,
        // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
        // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
        // operates on static or global value instead.
        bool DEFAULT_CTOR_ACQUIRE = true
    >
class Holder : public BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
                                 DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
{
    typedef BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
                                 DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;

  public:
    FORCEINLINE Holder()
        : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Holder(TYPE value)
        : BaseT(value)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Holder(TYPE value, BOOL takeOwnership) 
        : BaseT(value, takeOwnership)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Holder& operator=(TYPE p)
    {
        STATIC_CONTRACT_WRAPPER;
        BaseT::operator=(p);
        return *this;
    }

    HIDE_GENERATED_METHODS(Holder)
};

//---------------------------------------------------------------------------------------
// 
template
    <
        typename TYPE,
        void (*ACQUIREF)(TYPE),
        void (*RELEASEF)(TYPE),
        UINT_PTR DEFAULTVALUE = 0,
        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
        HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq,
        // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
        // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
        // operates on static or global value instead.
        bool DEFAULT_CTOR_ACQUIRE = true
    >
class Wrapper : public BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
                                   DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
{
    typedef BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
                                   DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;

  public:
    FORCEINLINE Wrapper()
        : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Wrapper(TYPE value)
        : BaseT(value)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Wrapper(TYPE value, BOOL takeOwnership) 
        : BaseT(value, takeOwnership)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Wrapper& operator=(TYPE const & value)
    {
        STATIC_CONTRACT_WRAPPER;
        BaseT::operator=(value);
        return *this;
    }

    HIDE_GENERATED_METHODS(Wrapper)
};  // Wrapper<>

//---------------------------------------------------------------------------------------
// - Cannot use the standard INDEBUG macro: holder.h is used in places where INDEBUG is defined in the nonstandard way
#if defined(_DEBUG)
#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) x
#else
#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x)
#endif 

//---------------------------------------------------------------------------------------
// 
// New template wrapper type macros.   These save some effort when specializing
// existing holder templates.  (We would rather use a construct like:
//
// template <P1>
// typedef Holder<...> NewHolder;
//
// But this construct doesn't exist in C++.  These macros ease some of the cruft necessary
// to get similar functionality out of class templates.
//----------------------------------------------------------------------------- 

// Dev10 VC++ has some of the new C++0x language extensions. Of particular interest here:
// rvalue references, which enables differentiation between named (lvalue) and
// temporary (rvalue) object references, enabling move semantics and perfect forwarding.
// See http://msdn.microsoft.com/en-us/library/dd293668.aspx for more information.

// Enable copy construction and assignment from temporary objects. This permits Wrapper objects
// to be returned from methods, and for move assignment.
#define NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME)                                             \
      public:                                                                                   \
        FORCEINLINE _NAME(_NAME && other)                                                       \
        : BaseT(NULL, FALSE)                                                                    \
        {                                                                                       \
            STATIC_CONTRACT_WRAPPER;                                                            \
            INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)                               \
            *this = std::move(other);                                                           \
        }                                                                                       \
        FORCEINLINE _NAME& operator=(_NAME && other)                                            \
        {                                                                                       \
            std::swap(BaseT::m_value, other.BaseT::m_value);                                    \
            std::swap(BaseT::m_acquired, other.BaseT::m_acquired);                              \
            return *this;                                                                       \
        }

#define NEW_WRAPPER_TEMPLATE1(_NAME, _RELEASEF)                                                 \
    template <typename _TYPE>                                                                   \
    class _NAME : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL>                    \
    {                                                                                           \
        typedef Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> BaseT;                      \
      public:                                                                                   \
        FORCEINLINE _NAME() : BaseT(NULL, FALSE)                                                \
        {                                                                                       \
            STATIC_CONTRACT_WRAPPER;                                                            \
            INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)                               \
        }                                                                                       \
        FORCEINLINE _NAME(_TYPE* value) : BaseT(value)                                          \
        {                                                                                       \
            STATIC_CONTRACT_WRAPPER;                                                            \
            INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)                               \
        }                                                                                       \
        FORCEINLINE _NAME(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership)       \
        {                                                                                       \
            STATIC_CONTRACT_WRAPPER;                                                            \
            INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)                               \
        }                                                                                       \
        FORCEINLINE ~_NAME()                                                                    \
        {                                                                                       \
        }                                                                                       \
        FORCEINLINE _NAME& operator=(_TYPE * value)                                             \
        {                                                                                       \
            STATIC_CONTRACT_WRAPPER;                                                            \
            BaseT::operator=(value);                                                            \
            return *this;                                                                       \
        }                                                                                       \
        /* Since operator& is overloaded we need a way to get a type safe this pointer. */      \
        FORCEINLINE _NAME* GetAddr()                                                            \
        {                                                                                       \
            STATIC_CONTRACT_LEAF;                                                               \
            return this;                                                                        \
        }                                                                                       \
        NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME)                                             \
        HIDE_GENERATED_METHODS(_NAME)                                                           \
      private:                                                                                  \
        /* m_ppValue: Do not use from source code: Only for convenient use from debugger */     \
        /*     watch windows - saves five mouseclicks when inspecting holders. */               \
        INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;)                                     \
    };

//-----------------------------------------------------------------------------
// NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!!
//  WE DO NOT CORRECTLY CHANGE TO PREEMPTIVE MODE BEFORE CALLING RELEASE!!
//  USE SafeComHolder
//
// ReleaseHolder : COM Interface holder for use outside the VM (or on well known instances
//                  which do not need preemptive Relesae)
//
// Usage example:
//
//  {
//      ReleaseHolder<IFoo> foo;
//      hr = FunctionToGetRefOfFoo(&foo); 
//      // Note ComHolder doesn't call AddRef - it assumes you already have a ref (if non-0).
//  } // foo->Release() on out of scope (WITHOUT RESPECT FOR GC MODE!!)
//
//-----------------------------------------------------------------------------

template <typename TYPE> 
FORCEINLINE void DoTheRelease(TYPE *value)
{
    if (value)
    {
        VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(HSV_ValidateNormalStackReq);
        value->Release();
    }
}

NEW_WRAPPER_TEMPLATE1(DoNothingHolder, DoNothing<_TYPE*>);

NEW_WRAPPER_TEMPLATE1(ReleaseHolder, DoTheRelease<_TYPE>);

NEW_WRAPPER_TEMPLATE1(NonVMComHolder, DoTheRelease<_TYPE>);


//-----------------------------------------------------------------------------
// StubHolder : holder for stubs
//
// Usage example:
//
//  {
//      StubHolder<Stub> foo;
//      foo = new Stub();
//      foo->AddRef();
//      // Note StubHolder doesn't call AddRef for you.
//  } // foo->DecRef() on out of scope
//
//-----------------------------------------------------------------------------
template <typename TYPE>
FORCEINLINE void StubRelease(TYPE* value)
{
    if (value)
        value->DecRef();
}

NEW_WRAPPER_TEMPLATE1(StubHolder, StubRelease<_TYPE>);

//-----------------------------------------------------------------------------
// CoTaskMemHolder : CoTaskMemAlloc allocated memory holder
//
//  {
//      CoTaskMemHolder<Foo> foo = (Foo*) CoTaskMemAlloc(sizeof(Foo));
//  } // delete foo on out of scope
//-----------------------------------------------------------------------------

template <typename TYPE> 
FORCEINLINE void DeleteCoTaskMem(TYPE *value)
{
    if (value)
        CoTaskMemFree(value);
}

NEW_WRAPPER_TEMPLATE1(CoTaskMemHolder, DeleteCoTaskMem<_TYPE>);

//-----------------------------------------------------------------------------
// NewHolder : New'ed memory holder
//
//  {
//      NewHolder<Foo> foo = new Foo ();
//  } // delete foo on out of scope
//-----------------------------------------------------------------------------

template <typename TYPE> 
FORCEINLINE void Delete(TYPE *value)
{
    STATIC_CONTRACT_LEAF;

    static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, WCHAR>::value,
                  "Must use NewArrayHolder (not NewHolder) for strings.");
    static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, CHAR>::value,
                  "Must use NewArrayHolder (not NewHolder) for strings.");
    
    delete value;
}

NEW_WRAPPER_TEMPLATE1(NewHolder, Delete<_TYPE>);

 //-----------------------------------------------------------------------------
// NewExecutableHolder : New'ed memory holder for executable memory.
//
//  {
//      NewExecutableHolder<Foo> foo = (Foo*) new (executable) Byte[num];
//  } // delete foo on out of scope
//-----------------------------------------------------------------------------
// IJW
template<class T> void DeleteExecutable(T *p);

NEW_WRAPPER_TEMPLATE1(NewExecutableHolder, DeleteExecutable<_TYPE>);
 
//-----------------------------------------------------------------------------
// NewArrayHolder : New []'ed pointer holder
//  {
//      NewArrayHolder<Foo> foo = new Foo [30];
//  } // delete [] foo on out of scope
//-----------------------------------------------------------------------------

template <typename TYPE> 
FORCEINLINE void DeleteArray(TYPE *value)
{
    STATIC_CONTRACT_WRAPPER;
    delete [] value;
    value = NULL;
}

NEW_WRAPPER_TEMPLATE1(NewArrayHolder, DeleteArray<_TYPE>);
typedef NewArrayHolder<CHAR>  AStringHolder;
typedef NewArrayHolder<WCHAR> WStringHolder;

//-----------------------------------------------------------------------------
// A special array holder that expects its contents are interface pointers,
// and will call Release() on them.
// 
// NOTE: You may ONLY use this if you've determined that it is SAFE to call
// Release() on the contained interface pointers (e.g., as opposed to SafeRelease)
// 
template <typename INTERFACE>
class NewInterfaceArrayHolder : public NewArrayHolder<INTERFACE *>
{
public:
    NewInterfaceArrayHolder() :
        NewArrayHolder<INTERFACE *>(),
        m_cElements(0) 
    {
        STATIC_CONTRACT_WRAPPER;
    }

    NewInterfaceArrayHolder& operator=(INTERFACE ** value)   
    {                                             
        STATIC_CONTRACT_WRAPPER;                  
        NewArrayHolder<INTERFACE *>::operator=(value);                  
        return *this;                             
    }                                             

    void SetElementCount(ULONG32 cElements)
    {
        STATIC_CONTRACT_LEAF;
        m_cElements = cElements;
    }

    ~NewInterfaceArrayHolder()
    {
        STATIC_CONTRACT_LEAF;
        for (ULONG32 i=0; i < m_cElements; i++)
        {
            if (this->m_value[i] != NULL)
                this->m_value[i]->Release();
        }
    }

protected:
    ULONG32 m_cElements;
};


//-----------------------------------------------------------------------------
// ResetPointerHolder : pointer which needs to be set to NULL
//  {
//      ResetPointerHolder<Foo> holder = &pFoo;
//  } // "*pFoo=NULL" on out of scope
//-----------------------------------------------------------------------------
#ifdef __GNUC__
// With -fvisibility-inlines-hidden, the Invoke methods below
// get hidden, which causes warnings when visible classes expose them.
#define VISIBLE __attribute__ ((visibility("default")))
#else
#define VISIBLE
#endif // __GNUC__

namespace detail
{
    template <typename T>
    struct ZeroMem
    {
        static VISIBLE void Invoke(T * pVal)
        {
            ZeroMemory(pVal, sizeof(T));
        }
    };

    template <typename T>
    struct ZeroMem<T*>
    {
        static VISIBLE void Invoke(T ** pVal)
        {
            *pVal = NULL;
        }
    };

}
#undef VISIBLE

NEW_WRAPPER_TEMPLATE1(ResetPointerHolder, detail::ZeroMem<_TYPE>::Invoke);
NEW_WRAPPER_TEMPLATE1(FieldNuller, detail::ZeroMem<_TYPE>::Invoke);

//-----------------------------------------------------------------------------
// Wrap win32 functions using HANDLE
//-----------------------------------------------------------------------------

FORCEINLINE void VoidCloseHandle(HANDLE h) { if (h != NULL) CloseHandle(h); }
// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
FORCEINLINE void VoidCloseFileHandle(HANDLE h) { if (h != ((HANDLE)((LONG_PTR) -1))) CloseHandle(h); }
FORCEINLINE void VoidFindClose(HANDLE h) { FindClose(h); }
FORCEINLINE void VoidUnmapViewOfFile(void *ptr) { UnmapViewOfFile(ptr); }

template <typename TYPE> 
FORCEINLINE void TypeUnmapViewOfFile(TYPE *ptr) { UnmapViewOfFile(ptr); }

// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
//@TODO: Dangerous default value. Some Win32 functions return INVALID_HANDLE_VALUE, some return NULL (such as CreatEvent).
typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseHandle, (UINT_PTR) -1> HandleHolder;
typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseFileHandle, (UINT_PTR) -1> FileHandleHolder;
typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidFindClose, (UINT_PTR) -1> FindHandleHolder;

typedef Wrapper<void *, DoNothing, VoidUnmapViewOfFile> MapViewHolder;

#ifdef WszDeleteFile
// Deletes a file with the specified path.  Do not use if you care about failures
// deleting the file, as failures are ignored by VoidDeleteFile.
FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); }
typedef Wrapper<LPCWSTR, DoNothing<LPCWSTR>, VoidDeleteFile, NULL> DeleteFileHolder;
#endif // WszDeleteFile

#if !defined(FEATURE_CORECLR) || defined(FEATURE_CRYPTO)
// Crypto holders
FORCEINLINE void VoidCryptReleaseContext(HCRYPTPROV h) { CryptReleaseContext(h, 0); }
FORCEINLINE void VoidCryptDestroyHash(HCRYPTHASH h) { CryptDestroyHash(h); }
FORCEINLINE void VoidCryptDestroyKey(HCRYPTKEY h) { CryptDestroyKey(h); }

typedef Wrapper<HCRYPTPROV, DoNothing, VoidCryptReleaseContext, 0> HandleCSPHolder;
typedef Wrapper<HCRYPTHASH, DoNothing, VoidCryptDestroyHash, 0> HandleHashHolder;
typedef Wrapper<HCRYPTKEY, DoNothing, VoidCryptDestroyKey, 0> HandleKeyHolder;
#endif // !FEATURE_CORECLR || FEATURE_CRYPTO

//-----------------------------------------------------------------------------
// Misc holders
//-----------------------------------------------------------------------------

// A holder for HMODULE.
FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); }

typedef Wrapper<HMODULE, DoNothing<HMODULE>, HolderFreeLibrary, NULL> HModuleHolder;

template <typename T> FORCEINLINE
void DoLocalFree(T* pMem) { (LocalFree)((HLOCAL)pMem); }

NEW_WRAPPER_TEMPLATE1(LocalAllocHolder, DoLocalFree<_TYPE>);

inline void BoolSet( _Out_ bool * val ) { *val = true; }
inline void BoolUnset( _Out_ bool * val ) { *val = false; }

typedef Wrapper< bool *, BoolSet, BoolUnset > BoolFlagStateHolder;

//
// We need the following methods to have volatile arguments, so that they can accept
// raw pointers in addition to the results of the & operator on Volatile<T>.
//

FORCEINLINE void CounterIncrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedIncrement(p);};
FORCEINLINE void CounterDecrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedDecrement(p);};

typedef Wrapper<RAW_KEYWORD(volatile) LONG*, CounterIncrease, CounterDecrease, (UINT_PTR)0, CompareDefault<RAW_KEYWORD(volatile) LONG*>, HSV_NoValidation> CounterHolder;


#ifndef FEATURE_PAL
FORCEINLINE void RegKeyRelease(HKEY k) {RegCloseKey(k);};
typedef Wrapper<HKEY,DoNothing,RegKeyRelease> RegKeyHolder;
#endif // !FEATURE_PAL

class ErrorModeHolder
{
    UINT m_oldMode;
public:
    ErrorModeHolder(UINT newMode){m_oldMode=SetErrorMode(newMode);};
    ~ErrorModeHolder(){SetErrorMode(m_oldMode);};
    UINT OldMode() {return m_oldMode;};
};

#ifndef FEATURE_PAL
//-----------------------------------------------------------------------------
// HKEYHolder : HKEY holder, Calls RegCloseKey on scope exit.
//
//  {
//      HKEYHolder hFoo = NULL;
//      WszRegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface",0, KEY_READ, hFoo);
//      
//  } // close key on out of scope via RegCloseKey.
//-----------------------------------------------------------------------------

class HKEYHolder
{
public:
    HKEYHolder()
    {
        STATIC_CONTRACT_LEAF;
        m_value = 0;
    }

    ~HKEYHolder()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_value != NULL)
            ::RegCloseKey(m_value);
    }

    FORCEINLINE void operator=(HKEY p)
    {
        STATIC_CONTRACT_LEAF;
        if (p != 0)
            m_value = p;
    }

    FORCEINLINE operator HKEY()
    {
        STATIC_CONTRACT_LEAF;
        return m_value;
    }

    FORCEINLINE operator HKEY*()
    {
        STATIC_CONTRACT_LEAF;
        return &m_value;
    }

    FORCEINLINE HKEY* operator&()
    {
        STATIC_CONTRACT_LEAF;
        return &m_value;
    }

private:
    HKEY m_value;
};
#endif // !FEATURE_PAL

//-----------------------------------------------------------------------------
// Wrapper to suppress auto-destructor (UNDER CONSTRUCTION)
// Usage:
//
//      BEGIN_MANUAL_HOLDER(NewArrayHolder<Foo>,  foo);
//      ... use foo via ->
//      END_MANUAL_HOLDER(foo);
// 
//-----------------------------------------------------------------------------

template <typename TYPE, SIZE_T SIZE = sizeof(TYPE)>
class NoAuto__DONTUSEDIRECTLY
{
  private:
    BYTE hiddeninstance[SIZE];

  public:
    // Unfortunately, you can only use the default constructor
    NoAuto__DONTUSEDIRECTLY()
    {
        new (hiddeninstance) TYPE ();
    }

    operator TYPE& () { return *(TYPE *)hiddeninstance; }
    TYPE& operator->() { return *(TYPE *)hiddeninstance; }
    TYPE& operator*() { return *(TYPE *)hiddeninstance; }

    void Destructor() { (*(TYPE*)hiddeninstance)->TYPE::~TYPE(); }
};

#define BEGIN_MANUAL_HOLDER(_TYPE, _NAME)           \
    {                                               \
        NoAuto__DONTUSEDIRECTLY<_TYPE> _NAME;       \
        __try                                       \
        {

#define END_MANUAL_HOLDER(_NAME)                    \
        }                                           \
        __finally                                   \
        {                                           \
            _NAME.Destructor();                     \
        }                                           \
    }

//----------------------------------------------------------------------------
//
// External data access does not want certain holder implementations
// to be active as locks should not be taken and so on.  Provide
// a no-op in that case.
//
//----------------------------------------------------------------------------

#ifndef DACCESS_COMPILE

#define DacHolder Holder

#else

template <typename TYPE, void (*ACQUIRE)(TYPE), void (*RELEASEF)(TYPE), UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, BOOL VALIDATE_BACKOUT_STACK = TRUE>
class DacHolder
{
  protected:
    TYPE    m_value;

  private:
    BOOL    m_acquired;      // Have we acquired the resource?

  public:
    FORCEINLINE DacHolder() 
      : m_value(TYPE(DEFAULTVALUE)), 
        m_acquired(FALSE)
    {
        STATIC_CONTRACT_SUPPORTS_DAC;
    }

    // construct a new instance of DacHolder
    // Arguments: 
    //     input:  value - the resource held
    //             take  - indicates whether the lock should be taken--the default is true. See Notes:
    // Note: In DAC builds, the Acquire function does not actually take the lock, instead
    //       it determines whether the lock is held (by the LS). If it is, the locked data
    //       is assumed to be inconsistent and the Acquire function will throw.
    FORCEINLINE DacHolder(TYPE value, BOOL take = TRUE) 
      : m_value(value), 
        m_acquired(FALSE)
    {
        STATIC_CONTRACT_SUPPORTS_DAC;
        if (take)
            Acquire();

    }
    FORCEINLINE ~DacHolder() 
    {
        STATIC_CONTRACT_SUPPORTS_DAC;
    }
    // Sets the value to 'value'. Doesn't call Acquire/Release if fTake is FALSE.
    FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
    {
        m_value = value;
    }
    FORCEINLINE void Acquire()
    {
        STATIC_CONTRACT_SUPPORTS_DAC;

        if (!IsNull())
        {
            m_acquired = TRUE;
            // because ACQUIRE is a template argument, if the line m_acquired = TRUE is placed after the call
            // where it logically belongs, the compiler flags it as "unreachable code." 
            ACQUIRE(this->m_value);
        }
    }
    FORCEINLINE void Release()
    {
        // Insert any global or thread bookeeping here

        if (m_acquired)
        {
            m_acquired = FALSE;
        }
    }
    FORCEINLINE void Clear()
    {
        m_value = TYPE(DEFAULTVALUE);
        m_acquired = FALSE;
    }
    FORCEINLINE void SuppressRelease()
    {
        m_acquired = FALSE;
    }
    FORCEINLINE TYPE GetValue()
    {
        return m_value;
    }
    FORCEINLINE BOOL IsNull() const
    {
        return IS_NULL(m_value, TYPE(DEFAULTVALUE));
    }

  private:
    FORCEINLINE DacHolder& operator=(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
    {
    }

    FORCEINLINE DacHolder(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
    {
    }
};

#endif // #ifndef DACCESS_COMPILE

// Holder-specific clr::SafeAddRef and clr::SafeRelease helper functions.
namespace clr
{
    template < typename ItfT > __checkReturn
    ItfT *
    SafeAddRef(ReleaseHolder<ItfT> & pItf)
    {
        STATIC_CONTRACT_LIMITED_METHOD;
        //@TODO: Would be good to add runtime validation that the return value is used.
        return SafeAddRef(pItf.GetValue());
    }

    namespace detail
    {
        template <typename T>
        char IsHolderHelper(HolderBase<T>*);
        int  IsHolderHelper(...);

        template <typename T>
        struct IsHolder : public std::conditional<
            sizeof(IsHolderHelper(reinterpret_cast<T*>(NULL))) == sizeof(char),
            std::true_type,
            std::false_type>::type
        {};
    }

    template < typename T >
    typename std::enable_if<detail::IsHolder<T>::value, ULONG>::type
    SafeRelease(T& arg)
    {
        STATIC_CONTRACT_LIMITED_METHOD;
        return arg.Release();
    }
}

#endif  // __HOLDER_H_
